/*
 * XmlSerializer.c
 *
 *  Created on: Feb 24, 2012
 *      Author: charbelchoueiri
 */
#include "common.h"

String* XmlSerialize(XmlNode* pRoot, String* sBuffer, bool bIndent)
{
	int32 iIndent = 0;
	XmlNode* pCurrent;
	XmlAttribute* pAttribute;
	wchar sNewLine[2] = L"\0\0";

	//If we need to indent then set the new line string.
	if (bIndent) sNewLine[0] =  L'\n';

	//If buffer is null then create it.
	if (sBuffer == null) sBuffer = StringCreate(1024);

	//add the document header if root node is a document.
	if (pRoot->nodeType == DOCUMENT_NODE) StringAppend(sBuffer, L"<?XML VERSION='1.0'?>%s%s", sNewLine, sNewLine);

	//If root is a document then start from the document element, otherwise start from the element.
	pCurrent = (pRoot->nodeType == DOCUMENT_NODE ? pRoot->firstChild : pRoot); //TODO: possibly call XmlDocumentElement to get the document element.

	//Serialize the current element and all it's children into the buffer.
	while (pCurrent != null)
	{
		if (pCurrent->nodeType == COMMENT_NODE)
		{
			StringAppend(sBuffer, L"<!--%s-->%s", pCurrent->nodeValue->value, sNewLine);
		}
		else if (pCurrent->nodeType == TEXT_NODE)
		{
			StringAppendXml(sBuffer, pCurrent->nodeValue->value);
		}
		else if (pCurrent->nodeType == ELEMENT_NODE)
		{
			//Indent if indentation is required.
			if (bIndent) StringAppendSpace(sBuffer, iIndent);

			//Append the element start tag and name.
			StringAppend(sBuffer, L"<%s", pCurrent->nodeName->value);

			//Append the attributes of the element.
			pAttribute = pCurrent->firstAttribute;
			while (pAttribute != null)
			{
				StringAppend(sBuffer, L" %s=\"%x\"", pAttribute->nodeName->value, pAttribute->nodeValue->value);
				pAttribute = pAttribute->nextSibling;
			}

			//If no children then close the tag otherwise append children.
			if (pCurrent->firstChild == null)
			{
				//If element has no value then close the element..
				if (pCurrent->nodeValue == null) StringAppend(sBuffer, L"/>%s", sNewLine);

				//Otherwise append the node value and use element close tag.
				else StringAppend(sBuffer, L"%s</%s>%s", pCurrent->nodeValue->value, pCurrent->nodeName->value, sNewLine);
			}
			//If element has children then append value if exists and move onto the children to serialize them.
			else
			{
				//Close element tag and append value if exists.
				StringAppend(sBuffer, L">%s", (pCurrent->nodeValue == null ? sNewLine : pCurrent->nodeValue->value));

				//Indent and move to the first child.
				iIndent += 2;
				pCurrent = pCurrent->firstChild;
				continue;
			}

			//If no more children and got back to the root then we are done.
			if (pCurrent == pRoot) return sBuffer;

			//Otherwise keep going non recursively.
			while (pCurrent->nextSibling == null)
			{
				iIndent -= 2;
				pCurrent = pCurrent->parentNode;

				//Terminate the current parent node.
				if (bIndent) StringAppendSpace(sBuffer, iIndent);
				StringAppend(sBuffer, L"</%s>%s", pCurrent->nodeName->value, sNewLine);

				//If we are back to the root then we are done.
				if (pCurrent == pRoot) return sBuffer;
			}

			//Move the next sibling for serialization.
			pCurrent = pCurrent->nextSibling;

		}
	}

	//Return the buffer containing the serialize element.
	return sBuffer;
}


